package com.hksj.ecm.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.hksj.cbm.dto.LargeScreenBaseDTO;
import com.hksj.cbm.entity.DeviceInstance;
import com.hksj.cbm.entity.SpaceModel;
import com.hksj.cbm.entity.SpecialityModel;
import com.hksj.cbm.mapper.LargeScreenBaseMapper;
import com.hksj.cbm.service.SpaceModelService;
import com.hksj.cbm.service.SpecialityModelService;
import com.hksj.cbm.vo.DeviceMetadataParseInfoVO;
import com.hksj.cbm.vo.LargeScreenDeviceModelVO;
import com.hksj.cbm.vo.LargeScreenFileVO;
import com.hksj.common.core.common.Constants;
import com.hksj.common.core.common.SpecialityModelCodeEnum;
import com.hksj.common.core.executor.ThreadPoolConfig;
import com.hksj.common.core.util.DateUtil;
import com.hksj.ecm.dto.EnergyCockpitBaseDTO;
import com.hksj.ecm.dto.EnergyCockpitDTO;
import com.hksj.ecm.dto.EnergyConsumptionCostDTO;
import com.hksj.ecm.mapper.EnergyCockpitMapper;
import com.hksj.ecm.vo.*;
import com.hksj.tdengine.taos.service.TaosService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author fjt
 * @data 2024/8/8 16:56
 * @describe 能耗监测驾驶舱
 */
@Slf4j
@Service
public class EnergyCockpitService {

    @Autowired
    private TaosService taosService;
    @Autowired
    private SpaceModelService spaceModelService;
    @Autowired
    private SpecialityModelService specialityModelService;
    @Autowired
    private EnergyTypeService energyTypeService;
    @Autowired
    private EnergyCockpitMapper energyCockpitMapper;
    @Autowired
    private ThreadPoolConfig threadPoolConfig;

    @Autowired
    private LargeScreenBaseMapper largeScreenBaseMapper;

    @Value("${hk.td-engine.db-name:jetlinks_clean_room}")
    private String tdEngineDbName;

    // 能源类型code: 水
    private static final String water = "water";
    // 能源类型code: 电
    private static final String electricity = "electricity";


    /**
     * 设备概览
     * @return
     */
    public List<EnergyDeviceOverviewVO> deviceOverView(EnergyCockpitBaseDTO dto){
        // 全部能耗设备
        CompletableFuture<EnergyDeviceOverviewVO> allFuture = CompletableFuture.supplyAsync(() ->
                deviceOverViewByType(dto, null), threadPoolConfig.energyConsumptionTaskExecutor());

        // 电量监测设备
        CompletableFuture<EnergyDeviceOverviewVO> electricityFuture = CompletableFuture.supplyAsync(() ->
                deviceOverViewByType(dto, SpecialityModelCodeEnum.DianB_product.getCode()), threadPoolConfig.energyConsumptionTaskExecutor());

        // 水量监测设备
        CompletableFuture<EnergyDeviceOverviewVO> waterFuture = CompletableFuture.supplyAsync(() ->
                deviceOverViewByType(dto, SpecialityModelCodeEnum.ShuiB_product.getCode()), threadPoolConfig.energyConsumptionTaskExecutor());

        List<EnergyDeviceOverviewVO> list = new ArrayList<>(3);
        list.add(allFuture.join());
        list.add(electricityFuture.join());
        list.add(waterFuture.join());
        return list;
    }


    /**
     * 查询指定产品类型的概览
     * @param productCategoryKey 产品类型代码(模糊查询，以特定字符开头)
     * @return
     */
    private EnergyDeviceOverviewVO deviceOverViewByType(EnergyCockpitBaseDTO dto, String productCategoryKey){
        List<DeviceInstance> deviceList = energyCockpitMapper.deviceOverView(dto, SpecialityModelCodeEnum.energy_consumption.getCode(), productCategoryKey);
        EnergyDeviceOverviewVO overviewVO = new EnergyDeviceOverviewVO();
        if (CollUtil.isEmpty(deviceList)){
            overviewVO.setOnlineRate(new BigDecimal(0.00));
            return overviewVO;
        }
        // 在线
        List<DeviceInstance> onLineDeviceList = deviceList.stream().
                filter(device -> "online".equals(device.getState()))
                .collect(Collectors.toList());
        // 离线
        List<DeviceInstance> offLineDeviceList = deviceList.stream().
                filter(device -> "offline".equals(device.getState()))
                .collect(Collectors.toList());

        // 未激活
        List<DeviceInstance> notActiveList = deviceList.stream().
                filter(device -> "notActive".equals(device.getState()))
                .collect(Collectors.toList());

        overviewVO.setTotal(deviceList.size());
        overviewVO.setDeviceCode(productCategoryKey);
        // 计算在线率
        BigDecimal onlineRate = new BigDecimal("0.00");
        if (CollUtil.isNotEmpty(onLineDeviceList)){
            onlineRate = new BigDecimal(onLineDeviceList.size()).divide(new BigDecimal(deviceList.size()),  5, BigDecimal.ROUND_HALF_UP);
            overviewVO.setOnlineRate(onlineRate.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP));
        }else {
            overviewVO.setOnlineRate(onlineRate);
        }

        overviewVO.setOnlineNum(CollUtil.isNotEmpty(onLineDeviceList) ? onLineDeviceList.size() : 0);
        overviewVO.setOfflineNum(CollUtil.isNotEmpty(offLineDeviceList) ? offLineDeviceList.size() : 0);
        overviewVO.setNotActiveNum(CollUtil.isNotEmpty(notActiveList) ? notActiveList.size() : 0);
        return overviewVO;
    }


    /**
     * 能耗趋势查询(指定空间位置内，所有电表或水表能耗的增量值变化趋势)
     * @param dto
     * @return
     */
    public List<EnergyTrendVO> energyTrend(EnergyCockpitDTO dto){
        String productCategoryKey = null;
        String property = null;
        if (water.equals(dto.getEnergyTypeCode())){
            // 水表
            productCategoryKey = SpecialityModelCodeEnum.ShuiB_product.getCode();
            // 累计流量
            property = SpecialityModelCodeEnum.Lei_ji_ll.getCode();
        }
        if (electricity.equals(dto.getEnergyTypeCode())){
            // 电表
            productCategoryKey = SpecialityModelCodeEnum.DianB_product.getCode();
            // 累计电量
            property = SpecialityModelCodeEnum.Lei_ji_dl.getCode();
        }
        dto.setProperty(property);
        // 查询符合要求的设备id
        List<DeviceInstance> deviceList = queryDeviceById(dto, SpecialityModelCodeEnum.energy_consumption.getCode(), productCategoryKey);
        if (CollUtil.isEmpty(deviceList)){
            return null;
        }
        // 按产品id分组，并将同一产品id的设备id放在同一个list中
        Map<String, List<String>> deviceMap = deviceList.stream().collect(
                Collectors.groupingBy(DeviceInstance::getProductId, Collectors.mapping(DeviceInstance::getId, Collectors.toList())));


        Date startTime = null;
        // 统计时间类型(0=日;1=月;2=年)
        if (Constants.ZERO_STR.equals(dto.getTimeType())){
            startTime = DateUtil.getYmdHms(DateUtil.getYmd() + " 00:00:00");
        }
        if (Constants.ONE_STR.equals(dto.getTimeType())){
            // 获取当前时间所在月份的第一天
            startTime = DateUtil.getFirstDayOfMonth();
        }
        if (Constants.TWO_STR.equals(dto.getTimeType())){
            // 获取当前时间所在年份的第一天
            startTime = DateUtil.getFirstDayOfYear();
        }
        dto.setStartTime(startTime);
        dto.setEndTime(DateUtil.getYmdHms(DateUtil.getYmd() + " 23:59:59"));

        // 把每个产品的历史能耗数据放入一个集合中，进行数据整理
        List<EnergyTrendVO> dataList = new ArrayList<>();
        deviceMap.forEach((key, value) -> {
            // 获取当前设备的历史检测数据所在的TDengine表名
            String tableName = String.format("properties_%S", key);
            //判断表是否存在
            Boolean existStable = taosService.checkStable("jetlinks_clean_room", tableName);
            if (existStable){
                dto.setDeviceIdList(value);
                /**
                 * 例如：8月份上报了 1、3、5、9；9月份上报了10、16、20、25，
                 * 那么这段时间总能耗为25-1=24，每个月的能耗为9-1(8月份的)，25-10(9月份的) 8+15 != 24，因为8月份的最大值9和9月份的最小值10之间相差了1
                 * 所以为了计算准确，在9月份的25-10基础上加上10-9
                 */
                List<EnergyTrendHistoryDataVO> voList = energyCockpitMapper.queryHistoryData(dto, "jetlinks_clean_room." + tableName);
                // 处理数据，计算能耗差值
                if (CollUtil.isNotEmpty(voList)){
                    // 按设备id分组，计算每个测量设备的差值
                    Map<String, List<EnergyTrendHistoryDataVO>> deviceHistoryMap = voList.stream().collect(Collectors.groupingBy(EnergyTrendHistoryDataVO::getDeviceId));
                    for(Map.Entry<String, List<EnergyTrendHistoryDataVO>> entry : deviceHistoryMap.entrySet()){
                        // 按时间升序排序
                        List<EnergyTrendHistoryDataVO> energyTrendHistoryDataVOList = entry.getValue().stream()
                                .sorted(Comparator.comparing(EnergyTrendHistoryDataVO::getUploadTime, Comparator.naturalOrder())).collect(Collectors.toList());
                        for (int i=0; i < energyTrendHistoryDataVOList.size(); i++){
                            EnergyTrendHistoryDataVO historyDataVO = energyTrendHistoryDataVOList.get(i);
                            Double energyValue = historyDataVO.getMaxConsumptionValue() - historyDataVO.getMinConsumptionValue();

                            // 如果存在上一个数据，则加上两个之间的差值
                            if (i -1 >= 0){
                                EnergyTrendHistoryDataVO previousHistoryDataVO = energyTrendHistoryDataVOList.get(i - 1);
                                energyValue = energyValue + (historyDataVO.getMinConsumptionValue() - previousHistoryDataVO.getMaxConsumptionValue());
                            }

                            EnergyTrendVO trendVO = new EnergyTrendVO();
                            trendVO.setDeviceId(entry.getKey());
                            trendVO.setUploadTime(historyDataVO.getUploadTime().replace("T", " "));
                            trendVO.setConsumptionValue(energyValue);
                            dataList.add(trendVO);
                        }
                    }
                }
            }
        });
        if (CollUtil.isEmpty(dataList)){
            return null;
        }

        // 按时间分组，对同一时间内的能耗求和
        Map<String, List<EnergyTrendVO>> dataMap = dataList.stream().collect(Collectors.groupingBy(EnergyTrendVO::getUploadTime));
        List<EnergyTrendVO> voList = new ArrayList<>(dataMap.size());
        dataMap.forEach((k, v) -> {
            EnergyTrendVO vo = new EnergyTrendVO();
            vo.setUploadTime(k);
            // 求和
            Double consumption = v.stream().mapToDouble(EnergyTrendVO::getConsumptionValue).sum();
            // 四舍五入保留2位小数
            vo.setConsumptionValue(new BigDecimal(consumption).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            voList.add(vo);
        });
        // 按时间升序排序
        return voList.stream().sorted(Comparator.comparing(EnergyTrendVO::getUploadTime, Comparator.naturalOrder())).collect(Collectors.toList());
    }


    /**
     *
     * @param dto 设备位置路径和科室字典明细值
     * @param specialityModelCode   专业编码
     * @param productCategoryKey    产品分类编码
     * @return 查询符合要求的设备id
     */
    private List<DeviceInstance> queryDeviceById(EnergyCockpitDTO dto, String specialityModelCode, String productCategoryKey){
        Assert.notNull(specialityModelCode, "专业编码不能为空");
        return energyCockpitMapper.queryDevice(dto, specialityModelCode, productCategoryKey);
    }


    /**
     * 能耗占比分析
     * @param dto
     * @return
     */
    public List<EnergyProportionVO> energyProportion(EnergyCockpitDTO dto){
        Date startTime = null;
        // 统计时间类型(0=日;1=月;2=年)
        if (Constants.ZERO_STR.equals(dto.getTimeType())){
            startTime = DateUtil.getYmdHms(DateUtil.getYmd() + " 00:00:00");
        }
        if (Constants.ONE_STR.equals(dto.getTimeType())){
            // 获取当前时间所在月份的第一天
            startTime = DateUtil.getFirstDayOfMonth();
        }
        if (Constants.TWO_STR.equals(dto.getTimeType())){
            // 获取当前时间所在年份的第一天
            startTime = DateUtil.getFirstDayOfYear();
        }
        dto.setStartTime(startTime);
        dto.setEndTime(DateUtil.getYmdHms(DateUtil.getYmd() + " 23:59:59"));
        // 查询各个产品的能耗
        Map<String, Double> energyMap = queryTotalEnergy(dto);
        if (CollUtil.isEmpty(energyMap)){
            return null;
        }
        // 计算总能耗
        Double total = energyMap.values().stream().mapToDouble(Double::doubleValue).sum();

        String productCategoryKey = null;
        if (water.equals(dto.getEnergyTypeCode())){
            productCategoryKey = SpecialityModelCodeEnum.ShuiB_product.getCode();
        }
        if (electricity.equals(dto.getEnergyTypeCode())){
            productCategoryKey = SpecialityModelCodeEnum.DianB_product.getCode();
        }

        // 查询指定种类的能源下都有哪些产品    同一分类的产品有可能有多个
        List<ProductCategoryVO> productCategoryVOList = energyCockpitMapper.queryProductCategory(productCategoryKey);
        if (CollUtil.isEmpty(productCategoryVOList)){
            return null;
        }
        // 产品分类code : 产品id
        Map<String, List<String>> productCategoryMap = productCategoryVOList.stream().collect(
                Collectors.groupingBy(ProductCategoryVO::getProductKey, Collectors.mapping(ProductCategoryVO::getProductId, Collectors.toList())));

        List<EnergyProportionVO> voList = new ArrayList<>(productCategoryMap.size());
        for(Map.Entry<String, List<String>> entry : productCategoryMap.entrySet()){
            BigDecimal detailEnergy = BigDecimal.ZERO;
            for(String productId : entry.getValue()){
                Double energy = energyMap.get(productId);
                if (ObjectUtil.isNotNull(energy)){
                    detailEnergy = detailEnergy.add(new BigDecimal(energy));
                }
            }
            // 计算占比  大于0
            if (detailEnergy.compareTo(BigDecimal.ZERO) == 1){
                EnergyProportionVO proportionVO = EnergyProportionVO.builder().key(entry.getKey()).keyName(SpecialityModelCodeEnum.getVal(entry.getKey())).build();
                BigDecimal proportion = detailEnergy.divide(new BigDecimal(total),  5, BigDecimal.ROUND_HALF_UP);
                proportionVO.setProportion(proportion.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP));
                voList.add(proportionVO);
            }
        }
        return voList;
    }


    /**
     * 查询水或电在指定时间内的每个产品的能耗值
     * @param dto
     * @return 产品id ：能耗值
     */
    public Map<String, Double> queryTotalEnergy(EnergyCockpitDTO dto){
        Assert.notNull(dto.getStartTime(), "查询起始时间不能为空");
        Assert.notNull(dto.getEndTime(), "查询截止时间不能为空");
        String productCategoryKey = null;
        String property = null;
        if (water.equals(dto.getEnergyTypeCode())){
            // 水表
            productCategoryKey = SpecialityModelCodeEnum.ShuiB_product.getCode();
            // 累计流量
            property = SpecialityModelCodeEnum.Lei_ji_ll.getCode();
        }
        if (electricity.equals(dto.getEnergyTypeCode())){
            // 电表
            productCategoryKey = SpecialityModelCodeEnum.DianB_product.getCode();
            // 累计电量
            property = SpecialityModelCodeEnum.Lei_ji_dl.getCode();
        }
        dto.setProperty(property);
        // 查询符合要求的设备id
        List<DeviceInstance> deviceList = queryDeviceById(dto, SpecialityModelCodeEnum.energy_consumption.getCode(), productCategoryKey);
        if (CollUtil.isEmpty(deviceList)){
            return null;
        }
        // 按产品id分组，并将同一产品id的设备id放在同一个list中
        Map<String, List<String>> deviceMap = deviceList.stream().collect(
                Collectors.groupingBy(DeviceInstance::getProductId, Collectors.mapping(DeviceInstance::getId, Collectors.toList())));

        // 把每个产品的历史能耗数据放入一个Map集合中，进行数据整理
        Map<String, Double> dataMap = new HashMap<>();
        deviceMap.forEach((key, value) -> {
            // 获取当前设备的历史检测数据所在的TDengine表名
            String tableName = String.format("properties_%S", key);
            //判断表是否存在
            Boolean existStable = taosService.checkStable("jetlinks_clean_room", tableName);
            if (existStable){
                dto.setDeviceIdList(value);
                // 计算同一类产品中每个符合要求的设备在指定时间段内的能耗
                List<DeviceEnergyVO> deviceEnergyVOList = energyCockpitMapper.queryHistoryEnergyGroupByDeviceId(dto, "jetlinks_clean_room." + tableName);
                if (CollUtil.isNotEmpty(deviceEnergyVOList)){
                    dataMap.put(key, deviceEnergyVOList.stream().mapToDouble(DeviceEnergyVO::getConsumptionValue).sum());
                }
            }
        });
        return dataMap;
    }


    /**
     * 能耗排名top10
     * @param dto
     * @return
     */
    public EnergyTopTenVo listTopTen(EnergyCockpitDTO dto){
        // 1.确定查询的时间范围
        Date startTime = null;
        // 统计时间类型(0=日;1=月;2=年)
        if (Constants.ZERO_STR.equals(dto.getTimeType())){
            startTime = DateUtil.getYmdHms(DateUtil.getYmd() + " 00:00:00");
        }
        if (Constants.ONE_STR.equals(dto.getTimeType())){
            // 获取当前时间所在月份的第一天
            startTime = DateUtil.getFirstDayOfMonth();
        }
        if (Constants.TWO_STR.equals(dto.getTimeType())){
            // 获取当前时间所在年份的第一天
            startTime = DateUtil.getFirstDayOfYear();
        }
        dto.setStartTime(startTime);
        dto.setEndTime(DateUtil.getYmdHms(DateUtil.getYmd() + " 23:59:59"));

        // 2.确定需要查询的设备
        String productCategoryKey = null;
        String property = null;
        if (water.equals(dto.getEnergyTypeCode())){
            // 水表
            productCategoryKey = SpecialityModelCodeEnum.ShuiB_product.getCode();
            // 累计流量
            property = SpecialityModelCodeEnum.Lei_ji_ll.getCode();
        }
        if (electricity.equals(dto.getEnergyTypeCode())){
            // 电表
            productCategoryKey = SpecialityModelCodeEnum.DianB_product.getCode();
            // 累计电量
            property = SpecialityModelCodeEnum.Lei_ji_dl.getCode();
        }
        // 能量类型
        dto.setProperty(property);
        // 查询符合要求的设备id
        List<DeviceInstance> deviceList = queryDeviceById(dto, SpecialityModelCodeEnum.energy_consumption.getCode(), productCategoryKey);
        if (CollUtil.isEmpty(deviceList)){
            return null;
        }
        // 按产品id分组，并将同一产品id的设备id放在同一个list中
        Map<String, List<String>> deviceMap = deviceList.stream().collect(
                Collectors.groupingBy(DeviceInstance::getProductId, Collectors.mapping(DeviceInstance::getId, Collectors.toList())));

        // 3.查询每类符合要求的设备的能耗
        List<DeviceEnergyVO> deviceEnergyVOList = new ArrayList<>(deviceList.size());
        for(Map.Entry<String, List<String>> entry : deviceMap.entrySet()){
            // 获取当前设备的历史检测数据所在的TDengine表名
            String tableName = String.format("properties_%S", entry.getKey());
            //判断表是否存在
            Boolean existStable = taosService.checkStable("jetlinks_clean_room", tableName);
            if (existStable){
                dto.setDeviceIdList(entry.getValue());
                List<DeviceEnergyVO> voList = energyCockpitMapper.queryHistoryEnergyGroupByDeviceId(dto, "jetlinks_clean_room." + tableName);
                if (CollUtil.isNotEmpty(voList)) {
                    voList = voList.stream().filter(item -> Double.compare(item.getConsumptionValue(), 0.0) != 0).collect(Collectors.toList());
                    deviceEnergyVOList.addAll(voList);
                }
            }
        }
        if (CollUtil.isEmpty(deviceEnergyVOList)){
            return null;
        }

        LambdaQueryWrapper<SpecialityModel> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SpecialityModel::getCode, SpecialityModelCodeEnum.energy_consumption.getCode());
        SpecialityModel specialityModel = specialityModelService.getOne(queryWrapper);
        if (ObjectUtil.isNull(specialityModel)){
            throw new RuntimeException("能耗监测系统缺少专业模型配置信息");
        }

        EnergyTopTenVo topTenVo = new  EnergyTopTenVo();
        if (StringUtils.isNotBlank(dto.getPaths())){
            SpaceModel spaceModel = spaceModelService.querySpaceModelByPaths(dto.getPaths());
            Assert.notNull(spaceModel, "空间模型表中不存在此路径");
            topTenVo.setSpaceItemValue(spaceModel.getSpaceItemValue());

            // 4.按要求，分组统计能耗
            if (Constants.FOUR_STR.equals(spaceModel.getSpaceItemValue())){
                // 是楼栋，则按科室或楼层排名    统计方式(1=按楼层统计 2=按科室统计)
                Integer statisticalMethod = specialityModel.getStatisticalMethod();
                EnergyTopTenBuildingVo buildingVo = new EnergyTopTenBuildingVo();
                buildingVo.setStatisticalMethod(statisticalMethod);
                if (Constants.ONE.equals(statisticalMethod)){
                    // 按楼层统计能耗(取前10)
                    buildingVo.setVoList(buildEnergyTopTenBuildingVo(deviceList, deviceEnergyVOList, dto.getPaths()));
                }
                if (Constants.TWO.equals(statisticalMethod)){
                    // 按科室统计能耗(取前10)
                    List<String> deviceDeptCodeList = deviceList.stream().map(DeviceInstance::getDepartmentItemValue).distinct().collect(Collectors.toList());
                    if (deviceDeptCodeList.stream().anyMatch(x -> StringUtils.isBlank(x))){
                        throw new RuntimeException("当前楼栋下的设备没有设置对应的所属科室");
                    }
                    buildingVo.setVoList(buildEnergyTopTenDepartmentVo(deviceList, deviceEnergyVOList));
                }
                topTenVo.setBuildingVo(buildingVo);

            }else {
                // 非楼栋，则按单个设备排名  按设备的能耗降序排序
                deviceEnergyVOList = deviceEnergyVOList.stream()
                        .sorted(Comparator.comparing(DeviceEnergyVO::getConsumptionValue, Comparator.reverseOrder()))
                        .collect(Collectors.toList());

                // 取前10的设备
                deviceEnergyVOList = deviceEnergyVOList.subList(0, Math.min(10, deviceEnergyVOList.size()));
                // 组装数据
                Map<String, String> deviceNameMap = deviceList.stream().collect(Collectors.toMap(p -> p.getId(), p -> p.getName()));
                List<EnergyTopTenDeviceDetailVo> deviceVoList = new ArrayList<>(10);
                deviceEnergyVOList.forEach(energyVo -> {
                    EnergyTopTenDeviceDetailVo deviceDetailVo = EnergyTopTenDeviceDetailVo.builder().deviceId(energyVo.getDeviceId())
                            .deviceName(deviceNameMap.get(energyVo.getDeviceId()))
                            // 四舍五入保留2位
                            .consumptionValue(new BigDecimal(energyVo.getConsumptionValue()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()).build();
                    deviceVoList.add(deviceDetailVo);
                });
                topTenVo.setDeviceVoList(deviceVoList);
            }

        }else {
            // 路径为空时默认按楼层或科室分组统计
            topTenVo.setSpaceItemValue(Constants.FOUR_STR);
            Integer statisticalMethod = specialityModel.getStatisticalMethod();
            EnergyTopTenBuildingVo buildingVo = new EnergyTopTenBuildingVo();
            buildingVo.setStatisticalMethod(statisticalMethod);
            if (Constants.ONE.equals(statisticalMethod)){
                // 按楼层统计能耗(取前10)
                buildingVo.setVoList(buildEnergyTopTenBuildingVo(deviceList, deviceEnergyVOList, dto.getPaths()));
            }
            if (Constants.TWO.equals(statisticalMethod)){
                // 按科室统计能耗(取前10)
                List<String> deviceDeptCodeList = deviceList.stream().map(DeviceInstance::getDepartmentItemValue).distinct().collect(Collectors.toList());
                if (deviceDeptCodeList.stream().anyMatch(x -> StringUtils.isBlank(x))){
                    throw new RuntimeException("当前楼栋下的设备没有设置对应的所属科室");
                }
                buildingVo.setVoList(buildEnergyTopTenDepartmentVo(deviceList, deviceEnergyVOList));
            }
            topTenVo.setBuildingVo(buildingVo);
        }

        return topTenVo;
    }


    /**
     * 按楼层统计能耗(取前10)
     * @param deviceList
     * @param deviceEnergyVOList
     * @param paths
     * @return
     */
    private List<EnergyTopTenBuildingVo.EnergyTopTenBuildingDetailVo> buildEnergyTopTenBuildingVo(List<DeviceInstance> deviceList,
                                                                                                  List<DeviceEnergyVO> deviceEnergyVOList, String paths){
        List<SpaceModel> spaceModelList = spaceModelService.querySpaceModelLikePaths(paths);
        if (CollUtil.isEmpty(spaceModelList)){
            throw new RuntimeException("数据异常！当前楼栋下没有设置楼层");
        }
        // 路径 ：楼层名称
        Map<String, String> spaceModeMap = spaceModelList.stream().collect(Collectors.toMap(p -> p.getPaths(), p -> p.getModelName()));
        // 设备id ：能耗值
        Map<String, Double> deviceEnergyMap = deviceEnergyVOList.stream().collect(Collectors.toMap(p -> p.getDeviceId(), p -> p.getConsumptionValue()));

        List<EnergyTopTenBuildingVo.EnergyTopTenBuildingDetailVo> list = new ArrayList<>(spaceModeMap.size());
        for(Map.Entry<String, String> entry : spaceModeMap.entrySet()){
            EnergyTopTenBuildingVo.EnergyTopTenBuildingDetailVo vo = EnergyTopTenBuildingVo.EnergyTopTenBuildingDetailVo.builder()
                    .floorName(entry.getValue()).build();
            // paths以当前楼层的路径开头的，则属于同一个楼层
            List<DeviceInstance> deviceFilterList = deviceList.stream().filter(item -> item.getPaths().startsWith(entry.getKey())).collect(Collectors.toList());
            if (CollUtil.isEmpty(deviceFilterList)){
                continue;
            }

            // 统计当前楼层的能耗总和
            BigDecimal consumptionValue = new BigDecimal("0.00");
            for(DeviceInstance deviceInstance : deviceFilterList){
                Double energy = deviceEnergyMap.get(deviceInstance.getId());
                consumptionValue = consumptionValue.add(new BigDecimal(ObjectUtil.isNotNull(energy) ? energy : 0.00));
            }
            // 四舍五入保留2位
            vo.setConsumptionValue(consumptionValue.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            list.add(vo);
        }

        // 按能耗降序排序
        list = list.stream().sorted(Comparator.comparing(EnergyTopTenBuildingVo.EnergyTopTenBuildingDetailVo::getConsumptionValue, Comparator.reverseOrder()))
                .collect(Collectors.toList());
        // 取前10
        return list.subList(0, Math.min(10, list.size()));
    }


    /**
     * 按科室统计能耗(取前10)
     * @param deviceList
     * @param deviceEnergyVOList
     * @return
     */
    private List<EnergyTopTenBuildingVo.EnergyTopTenBuildingDetailVo> buildEnergyTopTenDepartmentVo(
            List<DeviceInstance> deviceList, List<DeviceEnergyVO> deviceEnergyVOList){
        // 按科室分组
        Map<String, List<DeviceInstance>> deviceMap = deviceList.stream()
                .collect(Collectors.groupingBy(p -> p.getDepartmentItemValue() + "-" + p.getDepartmentItemValueName()));

        List<EnergyTopTenBuildingVo.EnergyTopTenBuildingDetailVo> list = new ArrayList<>(deviceMap.size());
        for (Map.Entry<String, List<DeviceInstance>> entry : deviceMap.entrySet()){
            String[] key = entry.getKey().split("-");
            EnergyTopTenBuildingVo.EnergyTopTenBuildingDetailVo vo = new EnergyTopTenBuildingVo.EnergyTopTenBuildingDetailVo();
            if (StringUtils.isNotBlank(key[0])){
                vo.setDepartmentItemValue(key[0]);
            }
            if (StringUtils.isNotBlank(key[1])){
                vo.setDepartmentItemValueName(key[1]);
            }

            // 统计当前科室的能耗总和
            BigDecimal consumptionValue = new BigDecimal("0.00");
            // 设备id ：能耗值
            Map<String, Double> deviceEnergyMap = deviceEnergyVOList.stream().collect(Collectors.toMap(p -> p.getDeviceId(), p -> p.getConsumptionValue()));
            for(DeviceInstance deviceInstance : entry.getValue()){
                Double energy = deviceEnergyMap.get(deviceInstance.getId());
                consumptionValue = consumptionValue.add(new BigDecimal(ObjectUtil.isNotNull(energy) ? energy : 0.00));
            }
            // 四舍五入保留2位
            vo.setConsumptionValue(consumptionValue.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            list.add(vo);
        }

        // 按能耗降序排序
        list = list.stream().sorted(Comparator.comparing(EnergyTopTenBuildingVo.EnergyTopTenBuildingDetailVo::getConsumptionValue, Comparator.reverseOrder()))
                .collect(Collectors.toList());
        // 取前10
        return list.subList(0, Math.min(10, list.size()));
    }


    /**
     * 能耗费用(驾驶舱页面中间费用计算接口)
     * @param dto
     * @return
     */
    public EnergyConsumptionCostVO energyConsumptionCost(EnergyConsumptionCostDTO dto){
        Date startTime = null;
        // 统计时间类型(0=日;1=月;2=年)
        if (Constants.ZERO_STR.equals(dto.getTimeType())){
            startTime = DateUtil.getYmdHms(DateUtil.getYmd() + " 00:00:00");
        }
        if (Constants.ONE_STR.equals(dto.getTimeType())){
            // 获取当前时间所在月份的第一天
            startTime = DateUtil.getFirstDayOfMonth();
        }
        if (Constants.TWO_STR.equals(dto.getTimeType())){
            // 获取当前时间所在年份的第一天
            startTime = DateUtil.getFirstDayOfYear();
        }
        // 当日、当月、当年
        dto.setStartTime(startTime);
        dto.setEndTime(DateUtil.getYmdHms(DateUtil.getYmd() + " 23:59:59"));

        // 当日或本月或今年的费用
        BigDecimal cost = new BigDecimal("0.00");
        EnergyConsumptionCostVO energyConsumptionCostVO = new EnergyConsumptionCostVO();

        // 当日或当月或当年的用水量
       CompletableFuture<Map<String, BigDecimal>> waterFuture = CompletableFuture.supplyAsync(() ->{
           EnergyCockpitDTO waterDTO = new EnergyCockpitDTO();
           BeanUtils.copyProperties(dto, waterDTO);
           waterDTO.setEnergyTypeCode(water);
           return calculateCostsAndEnergy(waterDTO);
       });

        // 当日或当月或当年的用电量
        CompletableFuture<Map<String, BigDecimal>> electricityFuture = CompletableFuture.supplyAsync(() ->{
            EnergyCockpitDTO electricityDTO = new EnergyCockpitDTO();
            BeanUtils.copyProperties(dto, electricityDTO);
            electricityDTO.setEnergyTypeCode(electricity);
            return calculateCostsAndEnergy(electricityDTO);
        });

        // 下面会改变查询的起始时间范围，所以要在此处拿到当前日、月、年的结果
        Map<String, BigDecimal> waterCostsAndEnergyMap = waterFuture.join();
        if (CollUtil.isNotEmpty(waterCostsAndEnergyMap)){
            energyConsumptionCostVO.setWaterEnergy(waterCostsAndEnergyMap.get("energy"));
            cost = cost.add(waterCostsAndEnergyMap.get("costs"));
        }else {
            energyConsumptionCostVO.setWaterEnergy(new BigDecimal("0.0"));
        }

        Map<String, BigDecimal> electricityCostsAndEnergyMap = electricityFuture.join();
        if (CollUtil.isNotEmpty(electricityCostsAndEnergyMap)){
            energyConsumptionCostVO.setElectricityEnergy(electricityCostsAndEnergyMap.get("energy"));
            cost = cost.add(electricityCostsAndEnergyMap.get("costs"));
        }else {
            energyConsumptionCostVO.setElectricityEnergy(new BigDecimal("0.0"));
        }
        if (BigDecimal.ZERO.compareTo(cost) == 0){
            energyConsumptionCostVO.setCost(cost);
        }else {
            energyConsumptionCostVO.setCost(cost.divide(new BigDecimal(10000),  4, BigDecimal.ROUND_HALF_UP));
        }

        // 计算昨日、上月、去年的起止时间
        Date previousStartTime = null;
        Date previousEndTime = null;
        // 统计时间类型(0=日;1=月;2=年)
        if (Constants.ZERO_STR.equals(dto.getTimeType())){
            // 昨日
            previousStartTime = DateUtil.getYesterday(dto.getStartTime());
            previousEndTime = DateUtil.getYesterday(dto.getEndTime());
        }
        if (Constants.ONE_STR.equals(dto.getTimeType())){
            // 上月
            previousStartTime = DateUtil.getLastMonth(dto.getStartTime());
            LocalDate localMonthDate = DateUtil.getLastDayOfReportingPeriod(previousStartTime);
            previousEndTime = DateUtil.getYmdHms(DateUtil.getFormatDate(localMonthDate, DateUtil.DEFAULT_FORMAT_DATE) + " 23:59:59");
        }
        if (Constants.TWO_STR.equals(dto.getTimeType())){
            // 去年
            previousStartTime = DateUtil.getLastYear(dto.getStartTime());
            LocalDate localYearDate = DateUtil.getLastDayOfYearToWhichBelongs(previousStartTime);
            previousEndTime = DateUtil.getYmdHms(DateUtil.getFormatDate(localYearDate, DateUtil.DEFAULT_FORMAT_DATE) + " 23:59:59");
        }
        EnergyCockpitDTO energyCockpitDTO = new EnergyCockpitDTO();
        BeanUtils.copyProperties(dto, energyCockpitDTO);
        energyCockpitDTO.setStartTime(previousStartTime);
        energyCockpitDTO.setEndTime(previousEndTime);

        // 昨日或上月或去年的用水量
        CompletableFuture<Map<String, BigDecimal>> previousWaterFuture = CompletableFuture.supplyAsync(() ->{
            energyCockpitDTO.setEnergyTypeCode(water);
            return calculateCostsAndEnergy(energyCockpitDTO);
        });

        // 昨日或上月或去年的用电量
        CompletableFuture<Map<String, BigDecimal>> previousElectricityFuture = CompletableFuture.supplyAsync(() ->{
            EnergyCockpitDTO previousElectricityDTO = new EnergyCockpitDTO();
            BeanUtils.copyProperties(energyCockpitDTO, previousElectricityDTO);
            previousElectricityDTO.setEnergyTypeCode(electricity);
            return calculateCostsAndEnergy(previousElectricityDTO);
        });

        Map<String, BigDecimal> previousWaterCostsAndEnergyMap = previousWaterFuture.join();
        // 昨日或上月或去年的费用
        BigDecimal previousCost = new BigDecimal("0.00");
        if (CollUtil.isNotEmpty(previousWaterCostsAndEnergyMap)){
            energyConsumptionCostVO.setPreviousWaterEnergy(previousWaterCostsAndEnergyMap.get("energy"));
            previousCost = previousCost.add(previousWaterCostsAndEnergyMap.get("costs"));
        }else {
            energyConsumptionCostVO.setPreviousWaterEnergy(new BigDecimal("0.0"));
        }

        Map<String, BigDecimal> previousElectricityCostsAndEnergyMap = previousElectricityFuture.join();
        if (CollUtil.isNotEmpty(previousElectricityCostsAndEnergyMap)){
            energyConsumptionCostVO.setPreviousElectricityEnergy(previousElectricityCostsAndEnergyMap.get("energy"));
            previousCost = previousCost.add(previousElectricityCostsAndEnergyMap.get("costs"));
        }else {
            energyConsumptionCostVO.setPreviousElectricityEnergy(new BigDecimal("0.0"));
        }
        if (BigDecimal.ZERO.compareTo(previousCost) == 0){
            energyConsumptionCostVO.setPreviousCost(previousCost);
        }else {
            energyConsumptionCostVO.setPreviousCost(previousCost.divide(new BigDecimal(10000), 4, BigDecimal.ROUND_HALF_UP));
        }

        return energyConsumptionCostVO;
    }


    /**
     * 计算能耗和费用
     * @param dto
     * @return
     */
    private Map<String, BigDecimal> calculateCostsAndEnergy(EnergyCockpitDTO dto){
        // 查询各个产品的能耗  产品id : 能耗值
        Map<String, Double> energyMap = queryTotalEnergy(dto);
        if (CollUtil.isEmpty(energyMap)){
            return null;
        }

        Map<String, BigDecimal> map = new HashMap<>(2);
        // 计算总能耗
        Double total = energyMap.values().stream().mapToDouble(Double::doubleValue).sum();
        map.put("energy", new BigDecimal(total).setScale(1, BigDecimal.ROUND_HALF_UP));

        // 计算费用
        String energyCode = null;
        if (water.equals(dto.getEnergyTypeCode())){
            // 水表
            energyCode = SpecialityModelCodeEnum.ShuiB_product.getCode();
        }
        if (electricity.equals(dto.getEnergyTypeCode())){
            // 电表
            energyCode = SpecialityModelCodeEnum.DianB_product.getCode();
        }
        map.put("costs", calculateCosts(energyCode, new BigDecimal(total)));
        return map;
    }


    /**
     * 计算费用
     * @param code      能源类型code
     * @param energy    能耗值
     * @return
     */
    private BigDecimal calculateCosts(String code, BigDecimal energy){
        if (BigDecimal.ZERO.compareTo(energy) >= 0){
            // energy <= 0
            return new BigDecimal("0.00");
        }
        EnergyTypeVO energyTypeVO = energyTypeService.queryEnergyRateByEnergyTypeCode(code);
        // 是否为计费能源(0=否 1=是)
        if (Constants.ZERO.equals(energyTypeVO.getBillingEnergyStatus())){
            return new BigDecimal("0.00");
        }
        // 阶梯费用是否开启(0=否 1=是)
        if (Constants.ZERO.equals(energyTypeVO.getLadderFeesStatus())){
            if (ObjectUtil.isNull(energyTypeVO.getUnitCost())){
                throw new RuntimeException("数据异常！" + energyTypeVO.getCode() + "的单价(非阶梯价)为空");
            }
            return new BigDecimal(energyTypeVO.getUnitCost()).multiply(energy);
        }

        List<EnergyRateVO> energyRateList = energyTypeVO.getEnergyRateList();
        if (CollUtil.isEmpty(energyRateList)){
            throw new RuntimeException(energyTypeVO.getCode() + "已开启阶梯计费，但查到的阶梯费率为空");
        }

        // 按范围起始值升序排序，能源阶梯费率是左闭右开的区间值，如：[0,100),[100,200),[200,300)
        energyRateList = energyRateList.stream()
                .sorted(Comparator.comparing(EnergyRateVO::getStartRangeValue, Comparator.naturalOrder()))
                .collect(Collectors.toList());

        // 需要进行计算的费率阶梯
        List<EnergyRateVO> calculationRateList = new ArrayList<>();
        for (EnergyRateVO energyRateVO : energyRateList){
            if (energy.compareTo(new BigDecimal(energyRateVO.getStartRangeValue())) == -1){
                // energy小于此阶梯起始值，则energy落在此阶梯之前的那一阶中
                break;
            }else {
                calculationRateList.add(energyRateVO);
            }
        }
        if (CollUtil.isEmpty(calculationRateList)){
            throw new RuntimeException(energyTypeVO.getCode() + "已开启阶梯计费，但查到的阶梯费率范围异常，消耗的能源：" + energy + "未落在任一阶梯费率中");
        }

        calculationRateList = calculationRateList.stream()
                .sorted(Comparator.comparing(EnergyRateVO::getStartRangeValue, Comparator.naturalOrder()))
                .collect(Collectors.toList());

        // 遍历calculationRateList，计算费用
        BigDecimal totalCosts = new BigDecimal("0.00");
        for(int i = 0; i < calculationRateList.size(); i++){
            EnergyRateVO energyRateVO = calculationRateList.get(i);
            // 费率
            BigDecimal unitCost = new BigDecimal(energyRateVO.getUnitCost());
            if (i == (calculationRateList.size() - 1)){
                // 如果是最后一级阶梯，则需要计算费用的能耗为：energy - 本级阶梯的起始值
                totalCosts = totalCosts.add(energy.subtract(new BigDecimal(energyRateVO.getStartRangeValue())).multiply(unitCost));
                break;
            }
            // 需要计算费用的能耗为：本级阶梯的截止值 - 本级阶梯的起始值
            totalCosts = totalCosts.add(new BigDecimal(energyRateVO.getEndRangeValue())
                    .subtract(new BigDecimal(energyRateVO.getStartRangeValue()))
                    .multiply(unitCost));
        }
        return totalCosts;
    }


    /**
     * 查询能耗大屏绑定的设备模型列表
     * @param dto 能耗数据传输对象
     * @return 大屏通用设备模型列表
     */
    public List<LargeScreenDeviceModelVO> queryEnergyCockpitBindDeviceModelList(EnergyConsumptionCostDTO dto) {

        //大屏基础数据传输对象
        LargeScreenBaseDTO largeScreenBaseDTO = new LargeScreenBaseDTO();

        //设置查询参数
        largeScreenBaseDTO.setDepartmentItemValue(dto.getDepartmentItemValue());
        largeScreenBaseDTO.setPaths(dto.getPaths());
        largeScreenBaseDTO.setSpecialityModelCode(SpecialityModelCodeEnum.energy_consumption.getCode());

        //查询已绑定的设备列表
        List<LargeScreenDeviceModelVO> largeScreenDeviceModelVOS = largeScreenBaseMapper.queryLargeScreenBindDeviceModelList(largeScreenBaseDTO);

        //若已绑定的设备列表为空、直接返回空的集合
        if (ObjectUtils.isEmpty(largeScreenDeviceModelVOS)){
            return new ArrayList<>();
        }

        //取出设备模型的列表中的文件id 组成文件id集合
        List<String> modelFileIdList = largeScreenDeviceModelVOS
                .stream()//转成stream流
                .map(LargeScreenDeviceModelVO::getModelFile)//将每个对象的modelFile属性取出,并返回
                .flatMap(modelFileId -> StrUtil.split(modelFileId, ",", -1, true, true).stream())//对modelFile属性进行扁平化处理,调用StrUtil.split进行字符串分隔,忽略空的modelFile,最后将其转换为stream流返回
                .collect(Collectors.toList());//将stream流收集,返回 modelFileIdList

        //判断文件id集合是否为空
        if (!ObjectUtils.isEmpty(modelFileIdList)){

            //若文件id集合不为空
            //通过文件id集合查询大屏文件集合
            List<LargeScreenFileVO> largeScreenFileList = largeScreenBaseMapper.queryLargeScreenFileList(modelFileIdList);

            //把文件集合设置到每个设备模型对象中
            largeScreenDeviceModelVOS.forEach(largeScreenDeviceModelVO -> {
                largeScreenFileList.forEach(largeScreenFileVO -> {
                    if (largeScreenDeviceModelVO.getModelFile() != null && largeScreenDeviceModelVO.getModelFile().contains(largeScreenFileVO.getId())){
                        largeScreenDeviceModelVO.getFileList().add(largeScreenFileVO);
                    }
                });
            });
        }


        //用电设备
        List<LargeScreenDeviceModelVO> useElectricityDeviceList = largeScreenDeviceModelVOS.stream().filter(deviceModelVO -> StringUtils.isNotBlank(deviceModelVO.getProductClassifiedCode()) && deviceModelVO.getProductClassifiedCode().startsWith("DianB")).collect(Collectors.toList());

        //用水设备
        List<LargeScreenDeviceModelVO> useWaterDeviceList = largeScreenDeviceModelVOS.stream().filter(deviceModelVO -> StringUtils.isNotBlank(deviceModelVO.getProductClassifiedCode()) && deviceModelVO.getProductClassifiedCode().startsWith("ShuiB")).collect(Collectors.toList());

        //设置今日用电能耗
        setEnergyOverPeriodTimeByDevice(useElectricityDeviceList,"DianB",1);

        //设置昨日用电能耗
        setEnergyOverPeriodTimeByDevice(useElectricityDeviceList,"DianB",0);

        //设置总电量
        setTotalEnergyByDevice(useElectricityDeviceList,"DianB");

        //设置今日用水能耗
        setEnergyOverPeriodTimeByDevice(useWaterDeviceList,"ShuiB",1);

        //设置昨日用水能耗
        setEnergyOverPeriodTimeByDevice(useWaterDeviceList,"ShuiB",0);

        //设置总水量
        setTotalEnergyByDevice(useWaterDeviceList,"ShuiB");

        return CollectionUtil.addAllIfNotContains(useElectricityDeviceList,useWaterDeviceList);
    }

    /**
     * 设置当前设备列表的能耗总量
     * @param deviceList 设备列表
     * @param energyType 能耗类型
     */
    public void setTotalEnergyByDevice(List<LargeScreenDeviceModelVO> deviceList, String energyType) {

        //获取设备id集合
        List<String> deviceIdList = deviceList.stream().map(LargeScreenDeviceModelVO::getDeviceId).collect(Collectors.toList());

        //若设备id为空、不需要设置能耗数据
        if(ObjectUtils.isEmpty(deviceIdList)){
            return;
        }

        //查询当前设备的总能耗
        List<EnergyPropertyVO> energyPropertyVOList = energyCockpitMapper.queryTotalEnergyByDevice(deviceIdList, energyType);

        //将查询的结果设置到设备列表
        deviceList.forEach(device -> {
            energyPropertyVOList.forEach(energyPropertyVO -> {

                //判断设备id是否相同
                if (Objects.equals(device.getDeviceId(),energyPropertyVO.getDeviceId())){

                    List<DeviceMetadataParseInfoVO> deviceMetadataParseInfoList = device.getDeviceMetadataParseInfoList();
                    DeviceMetadataParseInfoVO deviceMetadataParseInfoVO = new DeviceMetadataParseInfoVO();
                    deviceMetadataParseInfoVO.setValue(new BigDecimal(energyPropertyVO.getPropertyValue()).setScale(2, RoundingMode.HALF_UP).toString());
                    device.setUploadTime(energyPropertyVO.getUploadTime());
                    //判断是否为用电量
                    if (Objects.equals(energyType, "DianB")){

                        //判断是否为用电量
                        deviceMetadataParseInfoVO.setProperty("ydzl");
                        deviceMetadataParseInfoVO.setPropertyName("用电总量");
                        deviceMetadataParseInfoVO.setUnit("Kw.h");

                    } else {

                        //为用水量
                        deviceMetadataParseInfoVO.setProperty("yszl");
                        deviceMetadataParseInfoVO.setPropertyName("用水总量");
                        deviceMetadataParseInfoVO.setUnit("m³");
                    }

                    //将总能耗设置到设备中
                    deviceMetadataParseInfoList.add(deviceMetadataParseInfoVO);

                }
            });

        });
    }

    /**
     * 设置设备的能耗量
     * @param deviceList 设备集合
     * @param energyType 能耗类型
     * @param timeType 时间类型
     */
    public void setEnergyOverPeriodTimeByDevice(List<LargeScreenDeviceModelVO> deviceList, String energyType, int timeType) {

        //产品id集合
        Set<String> productIdSet = new HashSet<>();

        //将设备集合中的产品id取出、存入产品id集合
        deviceList.forEach(device -> {
            productIdSet.add(device.getProductId());
        });

        //遍历产品id集合、查询各产品对应的设备物模型数据
        productIdSet.forEach(productId -> {

            //超级表名称 jetlinks_clean_room.properties_产品id
            String stableName = String.format("properties_%s",productId);

            //完整的超级表名称 jetlinks_clean_room.properties_产品id
            String completeStableName = String.format("%s.properties_%s",tdEngineDbName,productId);

            //判断超级表是否存在
            Boolean checked = taosService.checkStable(tdEngineDbName, stableName);

            //若超级表存在、查询当前时间内的能耗明细
            if (checked){

                //查询当前时间内的能耗明细
                List<EnergyPropertyVO> energyPropertyVOList = energyCockpitMapper.queryEnergyOverPeriodTimeByDevice(completeStableName,energyType,timeType);

                //将查询结果设置到设备列表中
                deviceList.forEach(device ->{
                    energyPropertyVOList.forEach(energyPropertyVO -> {

                        //若设备id相同
                        if (Objects.equals(energyPropertyVO.getDeviceId(),device.getDeviceId())){
                            List<DeviceMetadataParseInfoVO> deviceMetadataParseInfoList = device.getDeviceMetadataParseInfoList();
                            DeviceMetadataParseInfoVO deviceMetadataParseInfoVO = new DeviceMetadataParseInfoVO();
                            deviceMetadataParseInfoVO.setValue(new BigDecimal(energyPropertyVO.getPropertyValue()).setScale(2,RoundingMode.HALF_UP).toString());
                            //判断查询的是今日的还是昨日的
                            if (timeType == 1){

                                //判断是否为用电量
                                if (Objects.equals(energyType, "DianB")){

                                    //判断是否为用电量
                                    deviceMetadataParseInfoVO.setProperty("jrydl");
                                    deviceMetadataParseInfoVO.setPropertyName("今日用电量");
                                    deviceMetadataParseInfoVO.setUnit("Kw.h");

                                } else {

                                    //为用水量
                                    deviceMetadataParseInfoVO.setProperty("jrysl");
                                    deviceMetadataParseInfoVO.setPropertyName("今日用水量");
                                    deviceMetadataParseInfoVO.setUnit("m³");
                                }

                            } else {

                                //为昨日的能耗
                                //判断是否为用电量
                                if (Objects.equals(energyType, "DianB")){

                                    //判断是否为用电量
                                    deviceMetadataParseInfoVO.setProperty("zrydl");
                                    deviceMetadataParseInfoVO.setPropertyName("昨日用电量");
                                    deviceMetadataParseInfoVO.setUnit("Kw.h");

                                } else {

                                    //为用水量
                                    deviceMetadataParseInfoVO.setProperty("jrysl");
                                    deviceMetadataParseInfoVO.setPropertyName("昨日用水量");
                                    deviceMetadataParseInfoVO.setUnit("m³");
                                }
                            }

                            //将解析的数据设置到设备解析数据列表
                            deviceMetadataParseInfoList.add(deviceMetadataParseInfoVO);
                        }
                    });
                });
            }

        });
    }


}
